package cn.mesmile.es.controller;

import cn.hutool.core.util.StrUtil;
import cn.mesmile.es.common.R;
import cn.mesmile.es.dao.BookRepository;
import cn.mesmile.es.entity.Book;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE;

/**
 * @author zb
 * @date 2021/6/9 18:24
 * @Description
 */
@RequestMapping("/api/v1/high")
@AllArgsConstructor
@RestController
public class HighClientController {

    private final ElasticsearchTemplate elasticsearchTemplate;

    private final RestHighLevelClient restHighLevelClient;

    @GetMapping("/query/{keyword}/{page}/{size}")
    public R queryPage (@PathVariable("keyword")String keyword,@PathVariable("page")int page, @PathVariable("size")int size) throws IOException {
        SearchRequest searchRequest = new SearchRequest("book");

        // 用于构建查询条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 查询条件
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("description", keyword);
        // 将查询条件放入构造器中
        searchSourceBuilder.query(matchQueryBuilder);

        // 设置页数
        searchSourceBuilder.from((page - 1) * size).size(size);

        // 将查询条件设置到检索请求
        searchRequest.source(searchSourceBuilder);

        // 发起请求
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits hits = search.getHits();
        long totalHits = hits.getTotalHits();
        System.out.println("totalHits = " + totalHits);

        SearchHit[] hits1 = hits.getHits();
        List<Book> bookList = new ArrayList<>(hits1.length);
        for (SearchHit documentFields : hits1) {
            String jsonString = documentFields.getSourceAsString();
            Book book = JSONObject.parseObject(jsonString, Book.class);
            bookList.add(book);
        }

        return R.data(bookList);
    }

    @GetMapping("/queryScroll")
    public R queryPage (@RequestParam("keyword")String keyword, @RequestParam("scrollId")String scrollId, @RequestParam("pageSize")int pageSize) throws IOException {
        SearchRequest searchRequest = null;
        SearchResponse search = null;
        // 第一次
        if (StrUtil.isEmpty(scrollId)) {
            searchRequest = new SearchRequest("book");
            // 用于构建查询条件
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            // 查询条件
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("description", keyword);

            // 设置高亮
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("description");
            highlightBuilder.preTags("<font color='red'>");
            highlightBuilder.postTags("</font>");

            // 将高亮信息放入构造器中
            searchSourceBuilder.highlighter(highlightBuilder);
            // 将查询条件放入构造器中
            searchSourceBuilder.query(matchQueryBuilder);

            // 设置每页显示条数
            searchSourceBuilder.size(pageSize);

            // 将查询条件设置到检索请求
            searchRequest.source(searchSourceBuilder);
            // 缓存 2 分钟
            searchRequest.scroll(TimeValue.timeValueMinutes(2));
            // 发起请求
            search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } else {
            // 第一次之后
            SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId);
            // 缓存 5 分钟
            searchScrollRequest.scroll(TimeValue.timeValueMinutes(5));
            search = restHighLevelClient.scroll(searchScrollRequest, RequestOptions.DEFAULT);
        }

        SearchHits hits = search.getHits();
        long totalHits = hits.getTotalHits();

        String scrollIdResult = search.getScrollId();

        SearchHit[] hits1 = hits.getHits();
        Map<String, Object> map = new HashMap<>();

        List<Book> bookList = new ArrayList<>(hits1.length);

        for (SearchHit documentFields : hits1) {
            String jsonString = documentFields.getSourceAsString();
            Book book = JSONObject.parseObject(jsonString, Book.class);

            // 封装高亮
            Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
            HighlightField descriptionHL = highlightFields.get("description");
            if (descriptionHL != null) {
                // 获取指定字段的高亮片段
                Text[] fragments = descriptionHL.getFragments();
                // 将这些高亮片段拼接成一个完整的高亮字段
                StringBuilder stringBuilder = new StringBuilder();
                for (Text fragment : fragments) {
                    stringBuilder.append(fragment);
                }
                book.setDescription(stringBuilder.toString());
            }

            bookList.add(book);
        }
        map.put("total", totalHits);
        map.put("context", bookList);
        map.put("scrollId", scrollIdResult);

        return R.data(map);
    }


    @GetMapping("/test")
    public R test() throws IOException {
        // 查询映射
        Map<String, Object> mapping = elasticsearchTemplate.getMapping(Book.class);
        // 字段以及值
        Map<String, Object> map = new HashMap<>();
        map.put("feature", "high-level-rest-client");
        map.put("age", 20);
        // index  type  id
        IndexRequest request = new IndexRequest("spring-data", "elasticsearch", "123")
                .source(map)
                .setRefreshPolicy(IMMEDIATE);
        IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
        RestStatus status = response.status();
        return R.data(status.getStatus());
    }
}
